<script lang="ts" setup>
import { ref, watch } from 'vue';
import { ElDialog, ElDescriptions, ElDescriptionsItem, ElTag, ElButton, ElMessage } from 'element-plus';
import { formatDateTime } from '@vben/utils';
import { severityMap } from './data';
import { getExceptionLogDetailApi, type LogApi } from '#/api/core/log';
import { $t } from '#/locales';

const props = defineProps<{
  id: string;
  visible: boolean;
}>();

const emit = defineEmits<{
  (e: 'update:visible', value: boolean): void;
}>();

// 详情数据
const loading = ref(false);
const detail = ref<LogApi.ExceptionLogDetailDto>();

// 监听对话框状态变化
watch(
  () => props.visible,
  async (visible) => {
    if (!visible || !props.id) return;

    loading.value = true;
    try {
      const response = await getExceptionLogDetailApi(props.id);
      detail.value = response;
    } catch (error) {
      console.error('获取异常详情失败:', error);
      ElMessage.error('获取异常详情失败');
    } finally {
      loading.value = false;
    }
  },
  { immediate: true }
);

// 复制文本到剪贴板
const copyToClipboard = async (text: string) => {
  try {
    await navigator.clipboard.writeText(text);
    ElMessage.success('复制成功');
  } catch (err) {
    ElMessage.error('复制失败');
  }
};

// 格式化堆栈信息，增加高亮显示
const formatStackTrace = (stackTrace: string) => {
  if (!stackTrace) return [];

  // 简单的语法高亮处理
  return stackTrace.split('\n').map((line) => {
    // 高亮错误信息行（通常是第一行）
    if (line.includes('Exception:') || line.includes('Error:')) {
      return `<span class="error-line">${line.trim()}</span>`;
    }
    // 高亮文件路径和行号
    return line.trim().replace(/(at .+) in (.+):(\d+)/, '$1 in <span class="file-path">$2</span>:<span class="line-number">$3</span>');
  });
};
</script>

<template>
  <ElDialog
    :model-value="visible"
    @update:model-value="(val: boolean) => emit('update:visible', val)"
    :title="$t('system.exceptionLog.detail')"
    width="80%"
    top="30px"
    :destroy-on-close="true"
    v-loading="loading"
    class="exception-detail-dialog"
  >
    <ElDescriptions
      v-if="detail"
      :column="2"
      border
      class="mb-4"
    >
      <ElDescriptionsItem :label="$t('system.exceptionLog.type')">
        <div class="detail-content">
          <span>{{ detail.exceptionType }}</span>
          <ElButton
            link
            type="primary"
            @click="copyToClipboard(detail.exceptionType)"
          >
            复制
          </ElButton>
        </div>
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.severity')">
        <ElTag :type="severityMap[detail.severity as keyof typeof severityMap]?.type || 'info'">
          {{ severityMap[detail.severity as keyof typeof severityMap]?.label || '未知' }}
        </ElTag>
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.time')" :span="2">
        {{ formatDateTime(detail.exceptionTime) }}
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.message')" :span="2">
        <div class="detail-content">
          <span>{{ detail.exceptionMessage }}</span>
          <ElButton
            link
            type="primary"
            @click="copyToClipboard(detail.exceptionMessage)"
          >
            复制
          </ElButton>
        </div>
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.source')" :span="2">
        {{ detail.source }}
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.path')">
        {{ detail.requestPath }}
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.method')">
        {{ detail.requestMethod }}
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.ip')">
        {{ detail.ipAddress }}
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.traceId')">
        <div class="detail-content">
          <span>{{ detail.traceId }}</span>
          <ElButton
            link
            type="primary"
            @click="copyToClipboard(detail.traceId)"
          >
            复制
          </ElButton>
        </div>
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.browser')">
        {{ detail.browser }}
      </ElDescriptionsItem>

      <ElDescriptionsItem :label="$t('system.exceptionLog.os')">
        {{ detail.os }}
      </ElDescriptionsItem>
    </ElDescriptions>

    <div v-if="detail?.stackTrace" class="stack-trace">
      <div class="stack-trace-header">
        <span>{{ $t('system.exceptionLog.stackTrace') }}</span>
        <div class="detail-content">
          <ElButton
            link
            type="primary"
            @click="copyToClipboard(detail.stackTrace)"
          >
            复制
          </ElButton>
        </div>
      </div>
      <div class="stack-trace-content">
        <pre><code v-html="formatStackTrace(detail.stackTrace).join('<br>')"></code></pre>
      </div>
    </div>

    <template #footer>
      <ElButton type="primary" @click="emit('update:visible', false)">
        关闭
      </ElButton>
    </template>
  </ElDialog>
</template>

<style lang="scss" scoped>
.exception-detail-dialog {
  :deep(.el-dialog__body) {
    padding: 20px;
  }

  :deep(.el-descriptions-item__content) {
    padding: 12px 16px;
  }
}

.detail-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;

  span {
    flex: 1;
    word-break: break-word;
  }
}

.stack-trace {
  margin-top: 16px;
  border: 1px solid var(--el-border-color);
  border-radius: 4px;

  &-header {
    padding: 8px 16px;
    background-color: var(--el-fill-color-light);
    border-bottom: 1px solid var(--el-border-color);
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  &-content {
    padding: 16px;
    background-color: var(--el-color-info-light-9);
    max-height: 400px;
    overflow-y: auto;

    pre {
      margin: 0;
      white-space: pre-wrap;
      word-wrap: break-word;
    }

    code {
      font-family: Consolas, Monaco, 'Andale Mono', monospace;
      font-size: 14px;
      line-height: 1.6;
      color: var(--el-text-color-primary);

      :deep(.error-line) {
        color: var(--el-color-danger);
        font-weight: bold;
      }

      :deep(.file-path) {
        color: var(--el-color-info);
      }

      :deep(.line-number) {
        color: var(--el-color-warning);
        font-weight: bold;
      }
    }
  }
}
</style>
